<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
	<title>字段中心式查询 | Elasticsearch: 权威指南 | Elastic</title>
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
	<link rel="stylesheet" type="text/css" href="../static/styles.css" />
</head>
<body>
<div class="main-container">
    <section id="content">
        
        <div class="content-wrapper">
            <section id="guide" lang="zh_cn">
                <div class="container">
                    <div class="row">
                        <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                            <div style="color:gray; word-break: break-all; font-size:12px;">原文地址: <a href="https://www.elastic.co/guide/cn/elasticsearch/guide/current/field-centric.html" rel="nofollow">https://www.elastic.co/guide/cn/elasticsearch/guide/current/field-centric.html</a>, 版权归 www.elastic.co 所有<br/>
                            英文版地址: <a href="https://www.elastic.co/guide/en/elasticsearch/guide/current/field-centric.html" rel="nofollow">https://www.elastic.co/guide/en/elasticsearch/guide/current/field-centric.html</a>
                            </div>
                        <!-- start body -->
                  <div class="page_header">
<b>请注意:</b><br>本书基于 Elasticsearch 2.x 版本，有些内容可能已经过时。
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch: 权威指南</a></span>
»
<span class="breadcrumb-link"><a href="search-in-depth.html">深入搜索</a></span>
»
<span class="breadcrumb-link"><a href="multi-field-search.html">多字段搜索</a></span>
»
<span class="breadcrumb-node">字段中心式查询</span>
</div>
<div class="navheader">
<span class="prev">
<a href="_cross_fields_entity_search.html">« 跨字段实体搜索</a>
</span>
<span class="next">
<a href="custom-all.html">自定义 _all 字段 »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="field-centric"></a>字段中心式查询<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/110_Multi_Field_Search/40_Field_centric.asciidoc">edit</a>
</h2>
</div></div></div>
<p>以上三个源于 <code class="literal">most_fields</code> 的问题都因为它是 <em>字段中心式（field-centric）</em> 而不是 <em>词中心式（term-centric）</em> 的：当真正感兴趣的是匹配词的时候，它为我们查找的是最匹配的 <em>字段</em> 。</p>
<div class="note admon">
<div class="icon"></div>
<div class="admon_content">
<p><code class="literal">best_fields</code> 类型也是字段中心式的，它也存在类似的问题。</p>
</div>
</div>
<p>首先查看这些问题存在的原因，再想如何解决它们。</p>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_问题_1_在多个字段中匹配相同的词"></a>问题 1 ：在多个字段中匹配相同的词<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/110_Multi_Field_Search/40_Field_centric.asciidoc">edit</a>
</h3>
</div></div></div>
<p>回想一下 <code class="literal">most_fields</code> 查询是如何执行的：Elasticsearch 为每个字段生成独立的 <code class="literal">match</code> 查询，再用 <code class="literal">bool</code> 查询将他们包起来。</p>
<p>可以通过 <code class="literal">validate-query</code> API 查看：</p>
<div class="pre_wrapper lang-sense">
<pre class="programlisting prettyprint lang-sense">GET /_validate/query?explain
{
  "query": {
    "multi_match": {
      "query":   "Poland Street W1V",
      "type":    "most_fields",
      "fields":  [ "street", "city", "country", "postcode" ]
    }
  }
}</pre>
</div>
<div class="sense_widget" data-snippet="snippets/110_Multi_Field_Search/40_Entity_search_problems.json"></div>
<p>生成 <code class="literal">explanation</code> 解释：</p>
<pre class="literallayout">(street:poland   street:street   street:w1v)
(city:poland     city:street     city:w1v)
(country:poland  country:street  country:w1v)
(postcode:poland postcode:street postcode:w1v)</pre>

<p>可以发现， <em>两个</em> 字段都与 <code class="literal">poland</code> 匹配的文档要比一个字段同时匹配 <code class="literal">poland</code> 与 <code class="literal">street</code> 文档的评分高。</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_问题_2_剪掉长尾"></a>问题 2 ：剪掉长尾<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/110_Multi_Field_Search/40_Field_centric.asciidoc">edit</a>
</h3>
</div></div></div>
<p>在 <a class="xref" href="match-multi-word.html#match-precision" title="控制精度">匹配精度</a> 中，我们讨论过使用 <code class="literal">and</code> 操作符或设置 <code class="literal">minimum_should_match</code> 参数来消除结果中几乎不相关的长尾，或许可以尝试以下方式：</p>
<div class="pre_wrapper lang-sense">
<pre class="programlisting prettyprint lang-sense">{
    "query": {
        "multi_match": {
            "query":       "Poland Street W1V",
            "type":        "most_fields",
            "operator":    "and", <a id="CO75-1"></a><i class="conum" data-value="1"></i>
            "fields":      [ "street", "city", "country", "postcode" ]
        }
    }
}</pre>
</div>
<div class="sense_widget" data-snippet="snippets/110_Multi_Field_Search/40_Entity_search_problems.json"></div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO75-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>所有词必须呈现。</p>
</td>
</tr>
</table>
</div>
<p>但是对于 <code class="literal">best_fields</code> 或 <code class="literal">most_fields</code> 这些参数会在 <code class="literal">match</code> 查询生成时被传入，这个查询的 <code class="literal">explanation</code> 解释如下：</p>
<pre class="literallayout">(+street:poland   +street:street   +street:w1v)
(+city:poland     +city:street     +city:w1v)
(+country:poland  +country:street  +country:w1v)
(+postcode:poland +postcode:street +postcode:w1v)</pre>

<p>换句话说，使用 <code class="literal">and</code> 操作符要求所有词都必须存在于 <em>相同字段</em> ，这显然是不对的！可能就不存在能与这个查询匹配的文档。</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_问题_3_词频"></a>问题 3 ：词频<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/110_Multi_Field_Search/40_Field_centric.asciidoc">edit</a>
</h3>
</div></div></div>
<p>在 <a class="xref" href="relevance-intro.html" title="什么是相关性?">什么是相关</a> 中，我们解释过每个词默认使用 TF/IDF 相似度算法计算相关度评分：</p>
<div class="variablelist">
<dl class="variablelist">
<dt>
<span class="term">
词频
</span>
</dt>
<dd>
一个词在单个文档的某个字段中出现的频率越高，这个文档的相关度就越高。
</dd>
<dt>
<span class="term">
逆向文档频率
</span>
</dt>
<dd>
一个词在所有文档某个字段索引中出现的频率越高，这个词的相关度就越低。
</dd>
</dl>
</div>
<p>当搜索多个字段时，TF/IDF 会带来某些令人意外的结果。</p>
<p>想想用字段 <code class="literal">first_name</code> 和 <code class="literal">last_name</code> 查询 “Peter Smith” 的例子， Peter 是个平常的名 Smith 也是平常的姓，这两者都具有较低的 IDF 值。但当索引中有另外一个人的名字是 “Smith Williams” 时， Smith 作为名来说很不平常，以致它有一个较高的 IDF 值！</p>
<p>下面这个简单的查询可能会在结果中将 “Smith Williams” 置于 “Peter Smith” 之上，尽管事实上是第二个人比第一个人更为匹配。</p>
<div class="pre_wrapper lang-sense">
<pre class="programlisting prettyprint lang-sense">{
    "query": {
        "multi_match": {
            "query":       "Peter Smith",
            "type":        "most_fields",
            "fields":      [ "*_name" ]
        }
    }
}</pre>
</div>
<div class="sense_widget" data-snippet="snippets/110_Multi_Field_Search/40_Bad_frequencies.json"></div>
<p>这里的问题是 <code class="literal">smith</code> 在名字段中具有高 IDF ，它会削弱 “Peter” 作为名和 “Smith” 作为姓时低 IDF 的所起作用。</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_解决方案"></a>解决方案<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elasticsearch-cn/elasticsearch-definitive-guide/edit/cn/110_Multi_Field_Search/40_Field_centric.asciidoc">edit</a>
</h3>
</div></div></div>
<p>存在这些问题仅仅是因为我们在处理着多个字段，如果将所有这些字段组合成单个字段，问题就会消失。可以为 <code class="literal">person</code> 文档添加 <code class="literal">full_name</code> 字段来解决这个问题：</p>
<div class="pre_wrapper lang-js">
<pre class="programlisting prettyprint lang-js">{
    "first_name":  "Peter",
    "last_name":   "Smith",
    "full_name":   "Peter Smith"
}</pre>
</div>
<p>当查询 <code class="literal">full_name</code> 字段时：</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
具有更多匹配词的文档会比只有一个重复匹配词的文档更重要。
</li>
<li class="listitem">
<code class="literal">minimum_should_match</code> 和 <code class="literal">operator</code> 参数会像期望那样工作。
</li>
<li class="listitem">
姓和名的逆向文档频率被合并，所以 Smith 到底是作为姓还是作为名出现，都会变得无关紧要。
</li>
</ul>
</div>
<p>这么做当然是可行的，但我们并不太喜欢存储冗余数据。取而代之的是 Elasticsearch 可以提供两个解决方案——一个在索引时，而另一个是在搜索时——随后会讨论它们。</p>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="_cross_fields_entity_search.html">« 跨字段实体搜索</a>
</span>
<span class="next">
<a href="custom-all.html">自定义 _all 字段 »</a>
</span>
</div>
</div>

                  <!-- end body -->
                        </div>
                        <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                        
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </section>
</div>
<script src="../static/cn.js"></script>
</body>
</html>